﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Threading;

namespace E4D.AppFabric.Entities.Engine
{
    class SessionFactoryImpl : ISessionFactory
    {
        public ISession getLocalSession()
        {
            // Call the CreateRunspace() method to create the 
            // runspace. This call does not specify any 
            // configuration information such as a custom host 
            // or initial session state information.
            //Runspace rs = RunspaceFactory.CreateRunspace(new WSManConnectionInfo("", computerName, 0, "", "", null, 0));
            Runspace rs = RunspaceFactory.CreateRunspace();

            rs.Open();

            return new LocalSession(rs, new List<string> { { "DistributedCacheAdministration" }, { "DistributedCacheConfiguration" } });
        }

        public ISession getRemoteSesion(String hostName)
        {
            Uri serverUri = new Uri("http://" + hostName + ":5985/wsman");

            // Call the CreateRunspace() method to create the 
            // runspace. This call does not specify any 
            // configuration information such as a custom host 
            // or initial session state information.
            //Runspace rs = RunspaceFactory.CreateRunspace(new WSManConnectionInfo("", computerName, 0, "", "", null, 0));
            Runspace rs = RunspaceFactory.CreateRunspace(new WSManConnectionInfo(serverUri));

            rs.Open();

            return new Session(rs, new List<string> { { "DistributedCacheAdministration" }, { "DistributedCacheConfiguration" } });
        }

        //This class uses lock to prevent usage from different threads
        private class LocalSession : Session
        {
            private static readonly object sync = new object();
            private bool disposed;

            public LocalSession(Runspace runspace, ICollection<string> modules)
                : base(runspace, modules)
            {
                Monitor.Enter(sync);
            }

            ~LocalSession()
            {
                this.Dispose(false);
            }

            public override void Dispose()
            {
                this.Dispose(true);
                GC.SuppressFinalize(this);
            }

            protected virtual void Dispose(bool disposing)
            {
                if (disposing && !this.disposed)
                {
                    Monitor.Exit(sync);
                    base.Dispose();
                }

                this.disposed = true;
            }
        }
    }
}
